var tgd = tgd || {};
tgd.Tools = tgd.Tools || {};
tgd.Tools.ContactDiff = tgd.Tools.ContactDiff || {};

/*
 * represents a unique contact
 *
 * contact - tgd.Tools.ContactDiff.Contact
 *      TODO
 *
 * canvas - HTMLElement
 *      The container for in which this view should render itself.
 *
 * user - tgd.Tools.ContactDiff.User
 *      TODO
 */
tgd.Tools.ContactDiff.ContactView = function (contact, canvas, user) {
    var _contact = contact;
    var _canvas = canvas;
    var _show = true;
    var _user = user;
    var self = this;

    this.__defineGetter__("Contact", function() { return _contact; });

    this.Labels = {
        Name : _canvas.getElementsByClassName("lblName")[0],
        NumDiffs : _canvas.getElementsByClassName("lblDiffs")[0],
        NumMatches : _canvas.getElementsByClassName("lblMatches")[0]
    }

    this.Buttons = {
        Toggle : _canvas.getElementsByClassName("btnToggle")[0],
        Properties : {
            All : _canvas.getElementsByClassName("btnAll")[0],
            Equal : _canvas.getElementsByClassName("btnEqual")[0],
            Unequal : _canvas.getElementsByClassName("btnUnequal")[0],
        }
    }

    this.Panels = {
        Properties : _canvas.getElementsByClassName("panProperties")[0],
        Matches : _canvas.getElementsByClassName("panMatching")[0],
        Differences : _canvas.getElementsByClassName("panDiffs")[0],
        UserContacts : _canvas.getElementsByClassName("panUserContacts")[0],
        Switches : _canvas.getElementsByClassName("panSwitches")[0],
        Amounts : _canvas.getElementsByClassName("panAmounts")[0]
    }

    this.Repeaters = {
        Matching : _canvas.getElementsByClassName("repMatching")[0],
        Diffs : _canvas.getElementsByClassName("repDiffs")[0],
        UserContacts : _canvas.getElementsByClassName("repUserContacts")[0]
    }

    this.Labels.Name.textContent = _contact.Name;
    this.Labels.NumDiffs.textContent = _contact.NumPropertyDifferences;
    this.Labels.NumMatches.textContent = _contact.NumPropertyMatches;

    this.hide = function() {
        _canvas.hide();
    }

    this.show = function() {
        _canvas.show();
    }

    /*
     * show - boolean - optional - If provided determines if the contact data is expanded (TRUE) or collapsed (FALSE).
     */
    this.toggle = function(show) {
        if (show !== undefined) {
            _show = !show;
        }

        if (_show) {
            this.Panels.Properties.hide();
            this.Buttons.Toggle.textContent = "+";
            this.Buttons.Toggle.unpressed();
        } else {
            this.Panels.Properties.show();
            this.Buttons.Toggle.innerHTML = "&mdash;";
            this.Buttons.Toggle.pressed();
        }
        _show = !_show;
    }

    this.showAll = function() {
        this.Panels.Matches.show();
        this.Panels.Differences.show();
        this.Buttons.Properties.All.pressed();
        this.Buttons.Properties.Equal.unpressed();
        this.Buttons.Properties.Unequal.unpressed();
    }

    this.showMatches = function() {
        this.Panels.Matches.show();
        this.Panels.Differences.hide();
        this.Buttons.Properties.All.unpressed();
        this.Buttons.Properties.Equal.pressed();
        this.Buttons.Properties.Unequal.unpressed();
    }

    this.showDifferences = function() {
        this.Panels.Matches.hide();
        this.Panels.Differences.show();
        this.Buttons.Properties.All.unpressed();
        this.Buttons.Properties.Equal.unpressed();
        this.Buttons.Properties.Unequal.pressed();
    }

    this.Buttons.Properties.All.onclick = function() { self.showAll(); };
    this.Buttons.Properties.Equal.onclick = function() { self.showMatches(); };
    this.Buttons.Properties.Unequal.onclick = function() { self.showDifferences(); };
    this.Buttons.Toggle.onclick = function() { self.toggle(); };

    /*
     * TODO
     */
    this._getUserIndex = function(email) {
        var idx = -1;
        
        for (var i = 0; i < _contact.AllUsers.length; ++i) {
            if (_contact.AllUsers[i].Name === email) {
                idx = i;
                break;
            }
        }
        
        return idx;
    }

    /*
     * TODO - HACK - to display nested objects i need to unroll them
     * return - HTMLElement
     *      For complex properties returns div in the following format:
         <div>
            <div>
                Prop1 <b>Val1</b>
            </div>
            <div>
                Prop2
                    <div>
                        Prop2.1 <b>Val2.1</b>
                        ...
                    </div>
                    ...
            </div>
         </div>
     *
     *      For simple data returns div in the following format:
         <div>
            Val
         </div>
     *
     */
    this._unrollObject = function(obj) {
        var div = document.createElement("div");

	    if (typeof obj === "string" || typeof obj === "number") {
	        var bold = document.createElement("b");
	        bold.textContent = obj;
	        div.appendChild(bold);
	    } else {
		    for (var p in obj) {
		        var innerDiv = document.createElement("div");
		        innerDiv.innerHTML = p + " &mdash; ";
			    //var t = document.createTextNode(p);
			    //innerDiv.appendChild(t);
			    if (typeof obj[p] === "string" || typeof obj[p] === "number") {
			        var bold = document.createElement("b");
			        bold.textContent = obj[p];
				    innerDiv.appendChild(bold);
			    } else {
				    innerDiv.appendChild(this._unrollObject(obj[p]));
			    }
			    div.appendChild(innerDiv);
		    }
	    }

	    return div;
    }

    /*
     * obj - 
     * idx - 
     */
    this._addDiffRow = function(obj, idx) {
        var row;
        var cell;

        if (this.Repeaters.Diffs.rows.length === 0) {
            row = this.Repeaters.Diffs.insertRow(-1);
            cell = row.insertCell(0);
            for (var i = 0; i < _contact.AllUsers.length; ++i) {
                cell = row.insertCell(-1);
                cell.textContent = _contact.AllUsers[i].Name;
            }
        }

        row = this.Repeaters.Diffs.insertRow(-1);
        cell = row.insertCell(-1);
        cell.textContent = obj.Name;
        for (var i = 0; i < _contact.AllUsers.length; ++i) {
            cell = row.insertCell(-1);
        }

        if (obj.AllowMultiples) {
            for (var i = 0; i < obj.Values[idx].Users.length; ++i) {
                row.cells[this._getUserIndex(obj.Values[idx].Users[i].Name) + 1].appendChild(this._unrollObject(obj.Values[idx].Value));
            }
        } else {
            for (var i = 0; i < obj.Values.length; ++i) {
                for (var j = 0; j < obj.Values[i].Users.length; ++j) {
                    row.cells[this._getUserIndex(obj.Values[i].Users[j].Name) + 1].appendChild(this._unrollObject(obj.Values[i].Value));
                }
            }
        }
    }

    /*
     * obj - 
     * idx - 
     */
    this._addMatchRow = function(obj, idx) {
        var row = this.Repeaters.Matching.insertRow(-1);

        var cell = row.insertCell(0);
        cell.textContent = obj.Name;
        
        cell = row.insertCell(1);
        if (obj.AllowMultiples) {
            cell.appendChild(this._unrollObject(obj.Values[idx].Value));
        } else {
            var bold = document.createElement("b");
            bold.textContent = obj.Values[0].Value;
            cell.appendChild(bold);
        }
    }

    /*
     * TODO
     *
     * 
     */
    this._addUserContactValueRow = function(name, value) {
        var row = this.Repeaters.UserContacts.insertRow(-1);

        var cell = row.insertCell(0);
        cell.textContent = name;
        
        cell = row.insertCell(1);
        cell.appendChild(this._unrollObject(value));
    }

    /*
     * TODO: rename
     * properties - 
     */
    this._loadMatches = function(properties) {
	    for (var prop in properties) {
		    if (properties[prop] instanceof tgd.Tools.ContactDiff.Property) {
			    var propObj = properties[prop]; //tgd.Tools.ContactDiff.Property object

                if (_user !== undefined) {  //showing contacts for a specific user
                    if (propObj.Users.some( function (element, index, array) { return element === _user; } )) {
                        for (var i = 0; i < propObj.Values.length; ++i) {
                            if (propObj.Values[i].Users.some( function (element, index, array) { return element === _user; } )) {
                                this._addUserContactValueRow(propObj.Name, propObj.Values[i].Value);
                            }
                        }
                    }
                } else if (propObj.AllowMultiples) {
                    for (var i = 0; i < propObj.Values.length; ++i) {
                        if (propObj.Values[i].Users.length === _contact.AllUserCount) {
                            this._addMatchRow(propObj, i);
                        } else {
                            this._addDiffRow(propObj, i);
                        }
                    }
                } else {
                    if (!propObj.HasDiffs && propObj.UserCount === _contact.AllUserCount) {
                        this._addMatchRow(propObj);
                    } else {
                        this._addDiffRow(propObj);
                    }
                }
		    } else if (typeof properties[prop] === "string" || typeof properties[prop] === "number") {
			    console.error("This should never happen.  ", prop, properties[prop]);
		    } else if (properties[prop] instanceof Array) {
			    console.error("This should never happen.  ", prop, properties[prop]);
		    } else { //object
			    this._loadMatches(properties[prop]);
		    }
	    }

    }

    this._loadMatches(_contact.Properties);

    if (_user === undefined) {
        this.Panels.UserContacts.hide();
        if (_contact.IsUnique) {
            this.Repeaters.Matching.insertRow(-1).insertCell(-1).innerHTML = "&#x2205;";
        }

        if (_contact.IsIdentical) {
            this.Repeaters.Diffs.insertRow(-1).insertCell(-1).innerHTML = "&#x2205;";
        }
    } else {
        this.Panels.Matches.hide();
        this.Panels.Differences.hide();
        this.Panels.Switches.hide();
        this.Panels.Amounts.hide();
        //todo: hide other stuff
    }

}
